/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.server.core.services;

import java.io.Serializable;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import offset.nodes.Constants;
import offset.nodes.client.dialog.xpath.model.GetXPathSearch;
import offset.nodes.client.dialog.xpath.model.NewXPathSearch;
import offset.nodes.client.dialog.xpath.model.SaveAsXPathSearch;
import offset.nodes.client.dialog.xpath.model.SetXPathSearch;
import offset.nodes.client.model.ServerRequest;
import offset.nodes.client.model.ServerResponse;
import offset.nodes.server.error.model.ExceptionId;
import offset.nodes.server.error.model.LoggedException;
import offset.nodes.server.model.RepositoryModel;
import offset.nodes.server.search.controller.QueryAttribute;
import offset.nodes.server.search.model.SearchCache;
import offset.nodes.server.search.model.SearchEntry;
import offset.nodes.server.servlet.AbstractRepositoryService;
import offset.nodes.server.servlet.Service;
import offset.nodes.server.servlet.ServiceContainer;
import offset.nodes.server.servlet.ServiceMapping;

/**
 *
 * @author Walter L�tgenau
 */
public class SearchServices extends AbstractRepositoryService implements ServiceContainer {

    @Override
    public ServiceMapping[] getServiceMappings() {
        return new ServiceMapping[]{
                    new ServiceMapping(new NewXPathSearch.Request().getId(), new Service() {

                public Serializable service(ServerRequest request) throws Exception {
                    return newXPathSearch((NewXPathSearch.Request) request);
                }
            }, this),
                    new ServiceMapping(new GetXPathSearch.Request().getId(), new Service() {

                public Serializable service(ServerRequest request) throws Exception {
                    return getXPathSearch((GetXPathSearch.Request) request);
                }
            }, this),
                    new ServiceMapping(new SetXPathSearch.Request().getId(), new Service() {

                public Serializable service(ServerRequest request) throws Exception {
                    return setXPathSearch((SetXPathSearch.Request) request);
                }
            }, this),
                    new ServiceMapping(new SaveAsXPathSearch.Request().getId(), new Service() {

                public Serializable service(ServerRequest request) throws Exception {
                    return saveAsXPathSearch((SaveAsXPathSearch.Request) request);
                }
            }, this),};

    }

    protected NewXPathSearch.Response newXPathSearch(NewXPathSearch.Request request) throws RepositoryException {
        NewXPathSearch.Response response = new NewXPathSearch.Response(ServerResponse.RESULT_SUCCESS);

        Session session = getSession(request);

        Node parent = getNode(session.getRootNode(), request.getParent());

        Node node = parent.addNode(request.getName(), Constants.TYPENAME_XPATH_SEARCH);
        node.setProperty(Constants.PROP_CONTENT_TYPE, Constants.PARVALUE_SEARCH);
        node.setProperty(Constants.PROP_QUERY, request.getXpathQuery());

        session.save();

        return response;
    }

    protected SetXPathSearch.Response setXPathSearch(SetXPathSearch.Request request) throws RepositoryException {
        SetXPathSearch.Response response = new SetXPathSearch.Response(ServerResponse.RESULT_SUCCESS);

        Session session = getSession(request);

        Node xpath = getNode(session.getRootNode(), request.getPath());

        xpath.setProperty(Constants.PROP_QUERY, request.getXpathQuery());

        session.save();

        return response;
    }

    protected SaveAsXPathSearch.Response saveAsXPathSearch(SaveAsXPathSearch.Request request) throws Exception {
        SaveAsXPathSearch.Response response = new SaveAsXPathSearch.Response(ServerResponse.RESULT_SUCCESS);

        Session session = getSession(request);

        Node parent = getNode(session.getRootNode(), request.getParent());
        if (parent.hasNode(request.getName()))
            throw new LoggedException(ExceptionId.SAVE_AS_ALREADY_EXISTING);

        Node node = parent.addNode(request.getName(), Constants.TYPENAME_XPATH_SEARCH);
        node.setProperty(Constants.PROP_CONTENT_TYPE, Constants.PARVALUE_SEARCH);

        QueryAttribute sr = (QueryAttribute) getRequest().getSession().getAttribute(QueryAttribute.ATT_QUERY);
        if (sr == null)
            throw new LoggedException(ExceptionId.GENERAL_PARAMETER_ERROR);

        node.setProperty(Constants.PROP_QUERY, sr.getQuery());

        session.save();

        return response;
    }

    protected GetXPathSearch.Response getXPathSearch(GetXPathSearch.Request request) throws RepositoryException {
        GetXPathSearch.Response response = new GetXPathSearch.Response(ServerResponse.RESULT_SUCCESS);

        if (request.getKey() != null) {
            SearchEntry query = SearchCache.getInstance(getRequest()).getSearch(request.getKey());
            if (query == null)
                return new GetXPathSearch.Response(ServerResponse.RESULT_FAILURE);

            response.setXpathQuery(query.getValue());
            return response;
        }

        Session session = getSession(request);

        Node xpath = getNode(session.getRootNode(), request.getPath());

        response.setXpathQuery(xpath.getProperty(Constants.PROP_QUERY).getString());

        return response;
    }

    /**
     * Return a node with a relative path to the root. Create path nodes, if necessory
     *
     * @param root
     * @param path
     * @return
     * @throws javax.jcr.RepositoryException
     */
    protected Node getNode(Node root, String path) throws RepositoryException {
        RepositoryModel repositoryModel = new RepositoryModel(root.getSession());
        return repositoryModel.getNode(root, path);
    }
}
